

#include <idt.h>
#include <kernel.h>

struct __idt_entry __idt[256];
struct __idtr_info __idt_info;

extern void __isr_null();

void _idt_make_idt_entry(struct __idt_entry *entry, 
			 unsigned short low_offset,
			 unsigned int selector, 
			 unsigned int flags, 
			 unsigned int high_offset){

  entry->high_offset = high_offset;
  entry->low_offset = low_offset;
  entry->seg_selector = selector;
  entry->flags = flags;

}

void _idt_set_idtr_info(unsigned int addr, short limit){

  __idt_info.base_addr = addr;
  __idt_info.limit = limit;

}

void _idt_init_basic_idt(){

  /* First set all IDT entries to a non present entry. */
  /* Later the basic exceptions can be filled in along */
  /* with other entries by drivers and such.           */

  unsigned short high_offset = 0, low_offset = 0;

  high_offset = ((unsigned int)__isr_null) >> 16;
  low_offset = ((unsigned int)__isr_null) & 0xFFFF;

  int i;
  for ( i = 0; i < 256; i++){
    _idt_make_idt_entry(&(__idt[i]), low_offset, 0x08, 
	     __IDT_PRIVLEGED | __IDT_32BIT_GATE | __IDT_PRESENT, high_offset);
  }

  /* Now fill in the important interrupts. */
  idt_install_idt_entry(0, __idt_interrupt_0, 
			__IDT_PRIVLEGED | __IDT_32BIT_GATE | __IDT_PRESENT,
			0x08);

  /* Flush the IDT. */
  __idt_info.base_addr = (unsigned int) &__idt;
  __idt_info.limit = 8 * 256;
  _idt_print_idt_entry(0);
  _idt_print_idt_entry(1);
  _idt_print_idt_entry(2);
  _flush_idt();
  _idt_print_idtr();

}

void idt_install_idt_entry(unsigned int entry, void (addr)(), 
			   unsigned short flags, unsigned short selector){

  unsigned int uint_addr = (unsigned int) addr;
  unsigned short high_offset = uint_addr >> 16;
  unsigned short low_offset = uint_addr & 0xFFFF;
  _idt_make_idt_entry(&(__idt[entry]), low_offset, 
		      selector, flags, high_offset);

}

void _idt_print_idt_entry(unsigned int entry){

  unsigned int *ptr = (unsigned int *)&(__idt[entry]);
  char buf[33];
  
  k_print(" high 32 bits: ");
  itobs(*(ptr+1), buf);
  k_print(buf);

  itobs(*ptr, buf);
  k_print("\n  low 32 bits: ");
  k_print(buf);
  k_printl();

}

struct __idtr_info idt_tmp;

void _idt_print_idtr(){

  _store_idt();
  char buf[33];
  itobs(idt_tmp.base_addr, buf);
  k_print(" base address: ");
  k_print(buf);

  itobs((unsigned int) idt_tmp.limit, buf);
  k_print("\n        limit: ");
  k_print(buf);
  k_printl();

}

void __idt_interrupt_0(){
  k_print("Exception: Divide by zero exception.\n");
  __kernel_panic();
}

void __idt_interrupt_1(){
  k_print("Exception: Debug exception.\n");
  __kernel_panic();
}

void __idt_interrupt_3(){
  k_print("Exception: Breakpoint.\n");
  __kernel_panic();
}

void __idt_interrupt_4(){
  k_print("Exception: Overflow exception.\n");
  __kernel_panic();
}

void __idt_interrupt_5(){
  k_print("Exception: Bounds check.\n");
  __kernel_panic();
}

void __idt_interrupt_6(){
  k_print("Exception: Invalid opcode exception.\n");
  __kernel_panic();
}

void __idt_interrupt_7(){
  k_print("Exception: Coprocessor not available.\n");
  __kernel_panic();
}

void __idt_interrupt_8(){
  k_print("Exception: Double fault.\n");
  __kernel_panic();
}

void __idt_interrupt_9(){
  k_print("Exception: Coprocessor segment overrun.\n");
  __kernel_panic();
}

void __idt_interrupt_10(){
  k_print("Exception: Invalid TSS.\n");
  __kernel_panic();
}

void __idt_interrupt_11(){
  k_print("Exception: Segment not present.\n");
  __kernel_panic();
}

void __idt_interrupt_12(){
  k_print("Exception: Stack exception.\n");
  __kernel_panic();
}

void __idt_interrupt_13(){
  k_print("Exception: General protection exception.\n");
  __kernel_panic();
}

void __idt_interrupt_14(){
  k_print("Exception: Page fault.\n");
  __kernel_panic();
}

void __idt_interrupt_16(){
  k_print("Exception: Coprocessor error.\n");
  __kernel_panic();
}
